import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.metrics import mean_squared_error, mean_absolute_error, r2_score
from matplotlib.font_manager import FontProperties
# 使用 macOS 的中文字体，比如 "PingFang SC"
font_prop = FontProperties(fname="/System/Library/Fonts/Hiragino Sans GB.ttc")
def evaluate_interpolation(preds, obs, *,
                            log_transform=False,
                            remove_small_obs=True,
                            small_obs_thresh=0.1,
                            plot=True,
                            output_path=None):
    """
    评估插值效果的综合函数
    
    参数:
    - preds: 插值预测值（np.array）
    - obs: 观测值（np.array）
    - log_transform: 是否对数据做log1p变换后评估
    - remove_small_obs: 是否过滤小于 small_obs_thresh 的观测值
    - small_obs_thresh: 小值阈值，默认0.1mm
    - plot: 是否绘图展示误差分布
    
    返回:
    - dict格式的评估指标
    """
    preds = np.asarray(preds)
    obs = np.asarray(obs)
    print(f"初始数据数量: {len(preds)}")

    # 剔除NaN
    mask = ~np.isnan(preds) & ~np.isnan(obs)
    preds = preds[mask]
    obs = obs[mask]

    print(f"剔除 NaN 后的数据数量: {len(preds)}")
    if remove_small_obs:
        mask = obs > small_obs_thresh
        preds = preds[mask]
        obs = obs[mask]

    if log_transform:
        preds = np.log1p(preds)
        obs = np.log1p(obs)
    
    # 误差计算
    errors = preds - obs
    mae = mean_absolute_error(obs, preds)
    rmse = np.sqrt(mean_squared_error(obs, preds))
    bias = np.mean(errors)
    r = np.corrcoef(obs, preds)[0, 1]

    if not log_transform:
        relative_errors = np.abs(errors) / obs
        mape = np.mean(relative_errors) * 100
    else:
        mape = None  # 对数空间下不计算相对误差

    # 输出
    metrics = {
        "样本数": len(obs),
        "R（相关系数）": round(r, 4),
        "RMSE": round(rmse, 4),
        "MAE": round(mae, 4),
        "Bias": round(bias, 4),
        "平均相对误差（%）": round(mape, 2) if mape is not None else "未计算（对数空间）",
    }
    
     # 保存到Excel
    if output_path:
        df = pd.DataFrame(metrics, index=[0])
        df.to_excel(output_path, index=False)
        print(f"✅ 插值评估结果已写入: {output_path}")

    if plot:
        # 箱线图
        plt.figure(figsize=(12, 4))
        plt.subplot(1, 3, 1)
        plt.boxplot(errors, vert=True)
        plt.title("插值误差分布", fontproperties=font_prop)
        plt.ylabel("预测误差 (mm)", fontproperties=font_prop)
        plt.grid(True)

        # 散点图
        plt.subplot(1, 3, 2)
        plt.scatter(obs, errors, alpha=0.6)
        plt.axhline(0, color="r", linestyle="--")
        plt.title("误差 vs 观测降水", fontproperties=font_prop)
        plt.xlabel("观测 (mm)", fontproperties=font_prop)
        plt.ylabel("误差 (预测-观测)", fontproperties=font_prop)
        plt.grid(True)

        # 误差直方图
        plt.subplot(1, 3, 3)
        plt.hist(errors, bins=30, edgecolor='black', alpha=0.7)
        plt.title("误差直方图", fontproperties=font_prop)
        plt.xlabel("预测误差", fontproperties=font_prop)
        plt.ylabel("频数", fontproperties=font_prop)
        plt.grid(True)

        plt.tight_layout()
        plt.show()

    return metrics
